/*
 * Copyright 2017 requery.io
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.requery;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * Marks a type as persistable. When used with the annotation processor the processor will inspect
 * the given class and generate a corresponding Entity class that can be used by the persistence
 * store to perform query/create/update/delete operations. Note that only the fields in the class
 * annotated with {@link Entity} will be persisted fields in super or sub classes will not be
 * considered.
 *
 * @author Nikhil Purushe
 */
@Documented
@Target(TYPE)
@Retention(RUNTIME)
public @interface Entity {

    /**
     * @return the desired Entity name for the type. This class will be generated by the processor
     * in the same package as the type the annotation is placed on. This name is also used as the
     * table name unless a {@link Table} attribute is specified with a different name.
     * Defaults to empty, the processor will remove "Abstract" prefix from the class name if it
     * exists.
     */
    String name() default "";

    /**
     * @return the model group this entity belongs to. Can be used to separate entities belonging to
     * different models (databases/persistence stores) by the processor.
     */
    String model() default "";

    /**
     * @return the builder class used to construct this entity if it is {@link #immutable()}.
     * Note the builder class must have a zero-argument constructor that is either package visible
     * or public.
     */
    Class<?> builder() default void.class;

    /**
     * @return true if the given object should be cached by the entity store, false otherwise.
     */
    boolean cacheable() default true;

    /**
     * @return true if the entity should be trivially copyable. In which case the annotation
     * processor will generate a copy() method returning a shallow copy of the given object.
     */
    boolean copyable() default false;

    /**
     * @return false if they class being annotated as entity is not extendable and the annotation
     * processor should not generate a type extending or implementing it but instead generate only
     * the attribute meta information. Defaults to true unless this annotation is placed on a class
     * that is final then defaults to false.
     */
    boolean extendable() default true;

    /**
     * @return true if the entity object is immutable. If true the entity cannot have changeable
     * relations and will not have any state, this implies {@link #stateless()} is true.
     * Defaults to false however if this annotation is placed in conjunction with immutable type
     * annotations e.g. @AutoValue from Google on an object then defaults to true.
     */
    boolean immutable() default false;

    /**
     * @return true if the entity object should have state tracking disabled, which allows partial
     * updates of changed values only and automatic retrieval of not loaded properties. Defaults to
     * false, unless the entity is {@link #immutable()} in which case the value is true.
     */
    boolean stateless() default false;

    /**
     * Defines the name style of properties in the target entity e.g. for a property 'name' and
     * style set to {@link PropertyNameStyle#BEAN} would map to:
     * <pre><code>
     *  getName() {...}
     *  setName(String name) {...}
     * </code></pre>
     * vs for {@link PropertyNameStyle#NONE}:
     * <pre><code>
     *  name() {...}
     *  name(String name) {...}
     * </code></pre>
     * @return the name style of properties in the target entity.
     */
    PropertyNameStyle propertyNameStyle() default PropertyNameStyle.BEAN;

    /**
     * Defines the target visibility of properties in the target entity. Note this is not
     * applicable to abstract or immutable classes.
     *
     * @return the visibility level of properties in the target entity
     */
    PropertyVisibility propertyVisibility() default PropertyVisibility.PRIVATE;
}
